use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use crate::error::Error;
use crate::mapper::ValueMapper;
use crate::modeling::{
    Class, ClassAttributeBuilder, ClassBuilder, ClassGetter, ClassRelationBuilder,
    RelationRelatedType, ValueType,
};
use crate::modeling::{
    ClassAttributePersistence, ClassPersistence, ClassPersistenceBuilder, ClassPersistenceGetter,
    ClassRelation, ClassRelationGetter, Value,
};

use super::FormSchema;

const FORM_SCHEMA_ITEM_CLASS_IDENTIFIER: &'static str = "g01_form_schema_item";

const FORM_SCHEMA_ITEM_CLASS_NAME: &'static str = "form_schema_item";

const FORM_SCHEMA_ITEM_TABLE_NAME: &'static str = "_g01_meta_form_schema_items";

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "FormSchemaItemBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct FormSchemaItem {
    /// id
    pub id: i64,
    /// identifier
    pub schema_identifier: String,
    /// 名称 variable
    pub variable: String,
    /// title
    pub label: String,
    /// form_type
    pub item_type: String,
    /// required
    pub required: bool,
    /// show_on
    pub show_on: bool,
    /// 图标
    pub default_value: Option<String>,
    /// 图标
    pub placeholder: Option<String>,
    /// 图标
    pub max_length: Option<i32>,
    /// 创建时间
    pub created_at: i64,
    /// 更新时间
    pub updated_at: i64,
}

impl ValueMapper for FormSchemaItem {}
//
crate::impl_from_value!(FormSchemaItem);
crate::impl_class_persistence_getter!(FormSchemaItem, FORM_SCHEMA_ITEM_TABLE_NAME);
crate::impl_class_relations_getter!(
    FormSchemaItem,
    vec![ClassRelationBuilder::default()
        .src_identifier(FormSchema::get_identifier()?)
        .target_identifier(Self::get_identifier()?)
        .related_type(RelationRelatedType::Keys)
        .related_at("schema_identifier")
        .build()?]
);

impl ClassGetter for FormSchemaItem {
    fn get_name() -> anyhow::Result<String> {
        Ok(String::from(FORM_SCHEMA_ITEM_CLASS_NAME))
    }
    fn get_identifier() -> anyhow::Result<String> {
        Ok(String::from(FORM_SCHEMA_ITEM_CLASS_IDENTIFIER))
    }
    fn get_class() -> anyhow::Result<Class> {
        let mut attribute_builder = ClassAttributeBuilder::default();
        attribute_builder.class_identifier(FORM_SCHEMA_ITEM_CLASS_IDENTIFIER);

        let mut commons = crate::modeling::simple_attributes_with_builder(&attribute_builder)?;
        let mut append = vec![
            attribute_builder
                .clone()
                .name("schema_identifier")
                .title("schema_identifier")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("variable")
                .title("variable")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("label")
                .title("label")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("item_type")
                .title("item_type")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("required")
                .title("required")
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("show_on")
                .title("show_on")
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("default_value")
                .title("default_value")
                .data_type(ValueType::String)
                .build()?,
            attribute_builder
                .clone()
                .name("placeholder")
                .title("placeholder")
                .data_type(ValueType::Boolean)
                .build()?,
            attribute_builder
                .clone()
                .name("max_length")
                .title("max_length")
                .data_type(ValueType::Number)
                .build()?,
        ];
        append.append(&mut commons);
        append.sort_by(|a, b| a.position.cmp(&b.position));

        let clazz = ClassBuilder::default()
            .identifier(FORM_SCHEMA_ITEM_CLASS_IDENTIFIER)
            .name(FORM_SCHEMA_ITEM_CLASS_NAME)
            .data_is_type(true)
            .is_persistent(true)
            .primary_key(String::from("identifier"))
            .attributes(append)
            .build()?;
        Ok(clazz)
    }
}
